package sym.qrcode.style;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;

import sym.qrcode.encoder.ByteMatrix;
import sym.qrcode.encoder.Mosaic;
import sym.qrcode.encoder.MosaicMatrix;
import sym.qrcode.image.ImageMosaicMatrix;
import sym.qrcode.image.OutputImage;

public class TextureStyle implements ImageGenerator {

    OutputImage outputMatrix;
    public final static int MARGIN = 3;
    public final static int UP = 1;
    public final static int DOWN = 2;
    public final static int LEFT = 3;
    public final static int RIGHT = 4;
    public final static int RANGE = 3;
    public final static int GRAYSCALE = 35;
    double Amplitude = 1.0;
    BufferedImage foregroundImage = null;
    BufferedImage backgroundImage = null;
    BufferedImage findInnerImage = null;
    BufferedImage findOuterImage = null;
    BufferedImage dotImage = null;
    int scale = 0;
    BufferedImage resultImage = null;
    int lightDirection = UP;
    
    int margin = 0;
    int maxWidth = 0;
    int maxHeight = 0;
    int negWidth = 0;
    int negHeight = 0;
    int baseWidth = 0;
    int baseHeight = 0;
    public TextureStyle(OutputImage outputMatrix) {
        this.outputMatrix = outputMatrix;
    }

    public TextureStyle(OutputImage outputMatrix, BufferedImage fImage,
            BufferedImage bImage, BufferedImage dImage, BufferedImage iImage,
            BufferedImage oImage, int lightDirection) {
        this(outputMatrix, fImage, bImage, dImage, iImage, oImage);
        this.lightDirection = lightDirection;
    }

    public TextureStyle(OutputImage outputMatrix, BufferedImage fImage,
            BufferedImage bImage, BufferedImage dImage, BufferedImage iImage,
            BufferedImage oImage) {
        this.outputMatrix = outputMatrix;
         margin = 2
                * MARGIN
                * outputMatrix.getScale();
         maxWidth = outputMatrix.getMaxImageWidth() + outputMatrix.getNegtiveImageWidth()
                + margin;
         maxHeight = outputMatrix.getMaxImageHeight() + outputMatrix.getNegtiveImageHeight()
                + margin;
         negWidth = outputMatrix.getNegtiveImageWidth();
         negHeight = outputMatrix.getNegtiveImageHeight();
         baseWidth = negWidth + MARGIN
                * outputMatrix.getScale();
         baseHeight = negHeight +MARGIN
                * outputMatrix.getScale();
        this.foregroundImage = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
        this.foregroundImage.getGraphics().drawImage(
                fImage.getScaledInstance(
                maxWidth, maxHeight, Image.SCALE_SMOOTH),
                0, 0, null);

        this.backgroundImage = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
        this.backgroundImage.getGraphics().drawImage(
                bImage.getScaledInstance(
                maxWidth, maxHeight, Image.SCALE_SMOOTH),
                0, 0, null);

        this.dotImage = new BufferedImage(outputMatrix.getScale(),
                outputMatrix.getScale(), BufferedImage.TYPE_INT_RGB);
        this.dotImage.getGraphics().drawImage(
                dImage.getScaledInstance(outputMatrix.getScale(),
                outputMatrix.getScale(), Image.SCALE_SMOOTH), 0, 0,
                null);

        this.findInnerImage = new BufferedImage(outputMatrix.getScale() * 3,
                outputMatrix.getScale() * 3, BufferedImage.TYPE_INT_RGB);
        this.findInnerImage.getGraphics().drawImage(
                iImage.getScaledInstance(outputMatrix.getScale() * 3,
                outputMatrix.getScale() * 3, Image.SCALE_SMOOTH), 0, 0,
                null);

        this.findOuterImage = new BufferedImage(outputMatrix.getScale() * 7,
                outputMatrix.getScale() * 7, BufferedImage.TYPE_INT_RGB);
        this.findOuterImage.getGraphics().drawImage(
                oImage.getScaledInstance(outputMatrix.getScale() * 7,
                outputMatrix.getScale() * 7, Image.SCALE_SMOOTH), 0, 0,
                null);

        scale = outputMatrix.getScale();
    }

    @Override
    public BufferedImage getFinalImage() {
        // TODO Auto-generated method stub
         
        int finalWidth = maxWidth;
        int finalHeight = maxHeight;

        if (this.foregroundImage == null || this.backgroundImage == null
                || this.dotImage == null || this.findInnerImage == null
                || this.findOuterImage == null) {
            return null;
        }

        resultImage = new BufferedImage(finalWidth, finalHeight,
                BufferedImage.TYPE_INT_RGB);
        fillBackground();

        MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();
        ByteMatrix matrix = outputMatrix.getQrcode().getMatrix();
        for (int i = 0; i < m.getWidth(); i++) {
            for (int j = 0; j < m.getHeight(); j++) {
                if (!isImage(i, j)) {
                    if (matrix.get(i, j) != 0) {
                        if (isDot(i, j)) {
                            handleDot(i, j);
                            continue;
                        }
                        if (isLeftUp(i, j)) {
                            handleLeftUp(i, j);
                        } else if (isLeft(i, j)) {
                            handleLeftUpLeft(i, j);
                        } else if (isUp(i, j)) {
                            handleLeftUpUp(i, j);
                        } else {
                            handleLeftUpNone(i, j);
                        }

                        if (isRightUp(i, j)) {
                            handleRightUp(i, j);
                        } else if (isRight(i, j)) {
                            handleRightUpRight(i, j);
                        } else if (isUp(i, j)) {
                            handleRightUpUp(i, j);
                        } else {
                            handleRightUpNone(i, j);
                        }

                        if (isLeftBottom(i, j)) {
                            handleLeftBottom(i, j);
                        } else if (isLeft(i, j)) {
                            handleLeftBottomLeft(i, j);
                        } else if (isBottom(i, j)) {
                            handleLeftBottomBottom(i, j);
                        } else {
                            handleLeftBottomNone(i, j);
                        }

                        if (isRightBottom(i, j)) {
                            handleRightBottom(i, j);
                        } else if (isRight(i, j)) {
                            handleRightBottomRight(i, j);
                        } else if (isBottom(i, j)) {
                            handleRightBottomBottom(i, j);
                        } else {
                            handleRightBottomNone(i, j);
                        }
                    }
                }
            }
        }

        for (int i = 0; i < m.getWidth(); i++) {
            for (int j = 0; j < m.getHeight(); j++) {
                if (!isImage(i, j)) {
                    if (matrix.get(i, j) == 0) {
                        if (isWhiteLeftUp(i, j)) {
                            handleWhiteLeftUp(i, j);
                        }
                        if (isWhiteRightUp(i, j)) {
                            handleWhiteRightUp(i, j);
                        }
                        if (isWhiteLeftBottom(i, j)) {
                            handleWhiteLeftBottom(i, j);
                        }
                        if (isWhiteRightBottom(i, j)) {
                            handleWhiteRightBottom(i, j);
                        }
                    }
                }
            }
        }
        setShade();
        for (ImageMosaicMatrix m2 : outputMatrix.getMosaicList()) {
            for (int i2 = 0; i2 < m2.getWidth(); i2++) {
                for (int j2 = 0; j2 < m2.getHeight(); j2++) {
                    if (m2.getMatrix()[j2][i2].type == Mosaic.IMAGE) {
                        for (int p = 0; p < scale; p++) {
                            for (int q = 0; q < scale; q++) {
                                if (!isWhite(new Color(m2.getColorRGB(i2
                                        * scale + p, j2 * scale + q)))) {
                                    resultImage.setRGB(
                                            negWidth + MARGIN * scale + (m2.getX() + i2)
                                            * scale + p,
                                            negHeight + MARGIN * scale + (m2.getY() + j2)
                                            * scale + q,
                                            m2.getColorRGB(i2 * scale + p, j2
                                            * scale + q));
                                } else {
                                    resultImage.setRGB(
                                            negWidth + MARGIN * scale + (m2.getX() + i2)
                                            * scale + p,
                                            negHeight + MARGIN * scale + (m2.getY() + j2)
                                            * scale + q,
                                            backgroundImage.getRGB(negWidth + MARGIN
                                            * scale + (m2.getX() + i2)
                                            * scale + p, negHeight + MARGIN * scale
                                            + (m2.getY() + j2) * scale
                                            + q));
                                }
                            }
                        }
                    }
                }
            }
        }
        return resultImage;
    }

    private boolean isWhite(Color color) {
        // TODO Auto-generated method stub
        if (color.getRed() > WHITETHRESHOLD && color.getBlue() > WHITETHRESHOLD
                && color.getGreen() > WHITETHRESHOLD) {
            return true;
        }
        return false;
    }

    private void handleWhiteRightBottom(int i, int j) {
        // TODO Auto-generated method stub

        for (int p = scale / 2; p < scale; p++) {
            for (int q = scale / 2; q < scale; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 0) {
                    if (!handleWhiteFindpattern(i, j, p, q)) {
                        resultImage.setRGB(
                                negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q,
                                foregroundImage.getRGB(i * scale + p, j * scale
                                + q));
                    }
                }
            }
        }
    }

    private boolean handleWhiteFindpattern(int i, int j, int p, int q) {
        // TODO Auto-generated method stub
        Mosaic m = outputMatrix.getQrcode().getMosaicMatrix().get(i, j);
        int x = 0;
        int y = 0;
        if (m.type == Mosaic.CRUCIALFUNC
                && m.func_type == Mosaic.FIND_PATTERN_CENTER) {
            if (i < 7 && j < 7) {
                x = (i - 2) * scale + p;
                y = (j - 2) * scale + q;
            } else if (i < 7 && j > 7) {
                x = (i - 2) * scale + p;
                y = (5 - outputMatrix.getQrcode().getMosaicMatrix().getHeight() + j)
                        * scale + q;
            } else if (i > 7 && j < 7) {
                x = (5 - outputMatrix.getQrcode().getMosaicMatrix().getWidth() + i)
                        * scale + p;
                y = (j - 2) * scale + q;
            }
            resultImage.setRGB(negWidth + MARGIN * scale + i * scale + p, negHeight + MARGIN * scale
                    + j * scale + q, findInnerImage.getRGB(x, y));
        } else if (m.type == Mosaic.CRUCIALFUNC
                && m.func_type == Mosaic.FIND_PATTERN_OUTER) {
            if (i < 7 && j < 7) {
                x = i * scale + p;
                y = j * scale + q;
            } else if (i < 7 && j > 7) {
                x = i * scale + p;
                y = (7 - outputMatrix.getQrcode().getMosaicMatrix().getHeight() + j)
                        * scale + q;
            } else if (i > 7 && j < 7) {
                x = (7 - outputMatrix.getQrcode().getMosaicMatrix().getWidth() + i)
                        * scale + p;
                y = j * scale + q;
            }
            resultImage.setRGB(negWidth + MARGIN * scale + i * scale + p, negHeight + MARGIN * scale
                    + j * scale + q, findOuterImage.getRGB(x, y));
        } else {
            return false;
        }
        return true;
    }

    private void handleWhiteLeftBottom(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = scale / 2; q < scale; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 0) {
                    if (!handleWhiteFindpattern(i, j, p, q)) {
                        resultImage.setRGB(
                                negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q,
                                foregroundImage.getRGB(negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q));
                    }
                }
            }
        }
    }

    private void handleWhiteRightUp(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = 0; q < scale / 2; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 0) {
                    if (!handleWhiteFindpattern(i, j, p, q)) {
                        resultImage.setRGB(
                                negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q,
                                foregroundImage.getRGB(negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q));
                    }
                }
            }
        }
    }

    private void handleWhiteLeftUp(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = 0; q < scale / 2; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 0) {
                    if (!handleWhiteFindpattern(i, j, p, q)) {
                        resultImage.setRGB(
                                negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q,
                                foregroundImage.getRGB(negWidth + MARGIN * scale + i * scale + p,
                                negHeight + MARGIN * scale + j * scale + q));
                    }
                }
            }
        }
    }

    private void handleRightBottomNone(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = scale / 2; q < scale; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(negWidth + MARGIN * scale + i * scale + p, negHeight + MARGIN
                            * scale + j * scale + q, foregroundImage.getRGB(negWidth + MARGIN * scale + i * scale + p, negHeight + MARGIN
                            * scale + j * scale + q));
                }
            }
        }
    }

    private void handleRightBottomBottom(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = scale / 2; q < scale; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, baseHeight + j * scale + q, 
                            foregroundImage.getRGB(baseWidth + i
                            * scale + p, baseHeight + j * scale + q));
                }
            }
        }
    }

    private void handleRightBottomRight(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = scale / 2; q < scale; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, baseHeight + j * scale + q, 
                            foregroundImage.getRGB(baseWidth+i
                            * scale + p, baseHeight+j * scale + q));
                }
            }
        }
    }

    private void handleRightBottom(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = scale / 2; q < scale; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 1) {
                    if (!handleFindPattern(i, j, p, q)) {
                        resultImage.setRGB(
                                baseWidth + i * scale + p,
                                baseHeight + j * scale + q,
                                foregroundImage.getRGB(baseWidth  + i * scale + p, baseHeight+j * scale
                                + q));
                    }
                }
            }
        }
    }

    private void handleLeftBottomNone(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = scale / 2; q < scale; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth+ i * scale + p, baseHeight + j * scale + q,
                            foregroundImage.getRGB(baseWidth + i
                            * scale + p,baseHeight+ j * scale + q));
                }
            }
        }
    }

    private void handleLeftBottomBottom(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = scale / 2; q < scale; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, baseHeight + j * scale + q, 
                            foregroundImage.getRGB(baseWidth+i
                            * scale + p,baseHeight+j * scale + q));
                }
            }
        }
    }

    private void handleLeftBottomLeft(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = scale / 2; q < scale; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p,baseHeight+ j * scale + q));
                }
            }
        }
    }

    private void handleLeftBottom(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = scale / 2; q < scale; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 1) {
                    if (!handleFindPattern(i, j, p, q)) {
                        resultImage.setRGB(
                                baseWidth + i * scale + p,
                                baseHeight + j * scale + q,
                                foregroundImage.getRGB(baseWidth+i * scale + p, baseHeight+j * scale
                                + q));
                    }
                }
            }
        }
    }

    private void handleRightUpNone(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = 0; q < scale / 2; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p, baseHeight+j * scale + q));
                }
            }
        }
    }

    private void handleRightUpUp(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = 0; q < scale / 2; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p,baseHeight + j * scale + q));
                }
            }
        }
    }

    private void handleRightUpRight(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = 0; q < scale / 2; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p, baseHeight + j * scale + q));
                }
            }
        }
    }

    private void handleRightUp(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            for (int q = 0; q < scale / 2; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 1) {
                    if (!handleFindPattern(i, j, p, q)) {
                        resultImage.setRGB(
                                baseWidth + i * scale + p,
                                baseHeight + j * scale + q,
                                foregroundImage.getRGB(baseWidth + i * scale + p,baseHeight + j * scale
                                + q));
                    }
                }
            }
        }
    }

    private void handleLeftUpNone(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = 0; q < scale / 2; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p, baseHeight + j * scale + q));
                }
            }
        }
    }

    private void handleLeftUpUp(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = 0; q < scale / 2; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p, baseHeight+ j * scale + q));
                }
            }
        }
    }

    private void handleLeftUpLeft(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = 0; q < scale / 2; q++) {
                if (!handleFindPattern(i, j, p, q)) {
                    resultImage.setRGB(baseWidth+ i * scale + p, 
                            baseHeight+ j * scale + q, foregroundImage.getRGB(baseWidth + i
                            * scale + p, baseHeight + j * scale + q));
                }
            }
        }
    }

    private boolean handleFindPattern(int i, int j, int p, int q) {
        Mosaic m = outputMatrix.getQrcode().getMosaicMatrix().get(i, j);
        int x = 0;
        int y = 0;
        if (m.type == Mosaic.CRUCIALFUNC
                && m.func_type == Mosaic.FIND_PATTERN_CENTER) {
            if (i < 7 && j < 7) {
                x = (i - 2) * scale + p;
                y = (j - 2) * scale + q;
            } else if (i < 7 && j > 7) {
                x = (i - 2) * scale + p;
                y = (5 - outputMatrix.getQrcode().getMosaicMatrix().getHeight() + j)
                        * scale + q;
            } else if (i > 7 && j < 7) {
                x = (5 - outputMatrix.getQrcode().getMosaicMatrix().getWidth() + i)
                        * scale + p;
                y = (j - 2) * scale + q;
            }
            resultImage.setRGB(baseWidth + i * scale + p, baseHeight
                    + j * scale + q, findInnerImage.getRGB(x, y));
        } else if (m.type == Mosaic.CRUCIALFUNC
                && m.func_type == Mosaic.FIND_PATTERN_OUTER) {
            if (i < 7 && j < 7) {
                x = i * scale + p;
                y = j * scale + q;
            } else if (i < 7 && j > 7) {
                x = i * scale + p;
                y = (7 - outputMatrix.getQrcode().getMosaicMatrix().getHeight() + j)
                        * scale + q;
            } else if (i > 7 && j < 7) {
                x = (7 - outputMatrix.getQrcode().getMosaicMatrix().getWidth() + i)
                        * scale + p;
                y = j * scale + q;
            }
            resultImage.setRGB(baseWidth + i * scale + p, baseHeight
                    + j * scale + q, findOuterImage.getRGB(x, y));
        } else {
            return false;
        }
        return true;

    }

    private void handleLeftUp(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            for (int q = 0; q < scale / 2; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 1) {
                    if (!handleFindPattern(i, j, p, q)) {
                        resultImage.setRGB(
                                baseWidth + i * scale + p,
                                baseHeight + j * scale + q,
                                foregroundImage.getRGB(baseWidth + i * scale + p, baseHeight+ j * scale
                                + q));
                    }
                }
            }
        }
    }

    private void fillBackground() {
        // TODO Auto-generated method stub
        MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();

        for (int i = 0; i < resultImage.getWidth(); i++) {
            for (int j = 0; j < resultImage.getHeight(); j++) {
                        resultImage.setRGB(
                                i,
                                j,
                                backgroundImage.getRGB(i ,j));

            }

        }
    }

    private void handleDot(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale; p++) {
            for (int q = 0; q < scale; q++) {
                int flag = isInCircle(p, q, scale / 2.0, scale / 2.0,
                        scale / 2.0);
                if (flag == 1 || flag == 2) {

                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight + j * scale + q, dotImage.getRGB(p, q));
                } else {
                    resultImage.setRGB(
                            baseWidth + i * scale + p,
                            baseHeight + j * scale + q,
                            backgroundImage.getRGB(baseWidth + i * scale
                            + p, baseHeight + j * scale + q));
                }
            }
        }
    }

    private boolean setShade() {
        // TODO Auto-generated method stub
        MosaicMatrix m = outputMatrix.getQrcode().getMosaicMatrix();
        if (lightDirection == UP) {
            for (int i = 0; i < m.getWidth(); i++) {
                for (int j = 0; j < m.getHeight(); j++) {
                    if (!isImage(i, j)) {
                        if (j > 0) {
                            if (isWhiteLeftBottom(i, j - 1)
                                    && isWhiteRightBottom(i, j - 1)
                                    && isUp(i, j)) {
                                setWhiteUpShadeL(i, j);
                                setWhiteUpShadeR(i, j);
                                continue;
                            }
                            if (isWhiteLeftBottom(i, j - 1) && isUp(i, j)) {
                                setUpShadeR(i, j);
                                setWhiteUpShadeL(i, j);
                                continue;
                            }
                            if (isWhiteRightBottom(i, j - 1) && isUp(i, j)) {
                                setUpShadeL(i, j);
                                setWhiteUpShadeR(i, j);
                                continue;
                            }
                        }
                        if (isLeftUp(i, j)) {
                            setLeftUpShade(i, j);
                        }
                        if (isRightUp(i, j)) {
                            setRightUpShade(i, j);
                        }
                        if ((!(isLeftUp(i, j) || isRightUp(i, j)))
                                && isUp(i, j)) {
                            setUpShadeL(i, j);
                            setUpShadeR(i, j);
                        } else if (isLeftUp(i, j)
                                && (!isRightUp(i, j) && isUp(i, j))) {
                            setUpShadeR(i, j);
                        } else if ((!isLeftUp(i, j))
                                && (isRightUp(i, j) && isUp(i, j))) {
                            setUpShadeL(i, j);
                        }
                    }
                }
            }
        } else if (lightDirection == DOWN) {
            for (int i = 0; i < m.getWidth(); i++) {
                for (int j = m.getHeight() - 1; j >= 0; j--) {
                    if (!isImage(i, j)) {
                        if (j < m.getHeight() - 1) {
                            if (isWhiteLeftUp(i, j + 1)
                                    && isWhiteRightUp(i, j + 1)
                                    && isBottom(i, j)) {
                                setWhiteBottomShadeL(i, j);
                                setWhiteBottomShadeR(i, j);
                                continue;
                            }
                            if (isWhiteLeftUp(i, j + 1) && isBottom(i, j)) {
                                setBottomShadeR(i, j);
                                setWhiteBottomShadeL(i, j);
                                continue;
                            }
                            if (isWhiteRightUp(i, j + 1) && isBottom(i, j)) {
                                setBottomShadeL(i, j);
                                setWhiteBottomShadeR(i, j);
                                continue;
                            }
                        }
                        if (isLeftBottom(i, j)) {
                            setLeftBottomShade(i, j);
                        }
                        if (isRightBottom(i, j)) {
                            setRightBottomShade(i, j);
                        }
                        if ((!(isLeftBottom(i, j) || isRightBottom(i, j)))
                                && isBottom(i, j)) {
                            setBottomShadeL(i, j);
                            setBottomShadeR(i, j);
                        } else if (isLeftBottom(i, j)
                                && (!isRightBottom(i, j) && isBottom(i, j))) {
                            setBottomShadeR(i, j);
                        } else if ((!isLeftBottom(i, j))
                                && (isRightBottom(i, j) && isBottom(i, j))) {
                            setBottomShadeL(i, j);
                        }
                    }
                }
            }
        } else if (lightDirection == LEFT) {
            for (int i = 0; i < m.getWidth(); i++) {
                for (int j = m.getHeight() - 1; j >= 0; j--) {
                    if (!isImage(i, j)) {
                        if (i > 0) {
                            if (isWhiteRightUp(i - 1, j)
                                    && isWhiteRightBottom(i - 1, j)
                                    && isLeft(i, j)) {
                                setWhiteLeftShadeT(i, j);
                                setWhiteLeftShadeB(i, j);
                                continue;
                            }
                            if (isWhiteRightUp(i - 1, j) && isLeft(i, j)) {
                                setLeftShadeB(i, j);
                                setWhiteLeftShadeT(i, j);
                                continue;
                            }
                            if (isWhiteRightBottom(i - 1, j) && isLeft(i, j)) {
                                setLeftShadeT(i, j);
                                setWhiteLeftShadeB(i, j);
                                continue;
                            }
                        }
                        if (isLeftBottom(i, j)) {
                            setBottomLeftShade(i, j);
                        }
                        if (isLeftUp(i, j)) {
                            setUpLeftShade(i, j);
                        }
                        if ((!(isLeftBottom(i, j) || isLeftUp(i, j)))
                                && isLeft(i, j)) {
                            setLeftShadeT(i, j);
                            setLeftShadeB(i, j);
                        } else if (isLeftBottom(i, j)
                                && (!isLeftUp(i, j) && isLeft(i, j))) {
                            setLeftShadeT(i, j);
                        } else if ((!isLeftBottom(i, j))
                                && (isLeftUp(i, j) && isLeft(i, j))) {
                            setLeftShadeB(i, j);
                        }
                    }
                }
            }
        } else if (lightDirection == RIGHT) {
            for (int i = 0; i < m.getWidth(); i++) {
                for (int j = m.getHeight() - 1; j >= 0; j--) {
                    if (!isImage(i, j)) {
                        if (i < m.getWidth() - 1) {
                            if (isWhiteLeftUp(i + 1, j)
                                    && isWhiteLeftBottom(i + 1, j)
                                    && isRight(i, j)) {
                                setWhiteRightShadeT(i, j);
                                setWhiteRightShadeB(i, j);
                                continue;
                            }
                            if (isWhiteLeftUp(i + 1, j) && isRight(i, j)) {
                                setRightShadeB(i, j);
                                setWhiteRightShadeT(i, j);
                                continue;
                            }
                            if (isWhiteLeftBottom(i + 1, j) && isRight(i, j)) {
                                setRightShadeT(i, j);
                                setWhiteRightShadeB(i, j);
                                continue;
                            }
                        }
                        if (isRightBottom(i, j)) {
                            setBottomRightShade(i, j);
                        }
                        if (isRightUp(i, j)) {
                            setUpRightShade(i, j);
                        }
                        if ((!(isRightBottom(i, j) || isRightUp(i, j)))
                                && isRight(i, j)) {
                            setRightShadeT(i, j);
                            setRightShadeB(i, j);
                        } else if (isRightBottom(i, j)
                                && (!isRightUp(i, j) && isRight(i, j))) {
                            setRightShadeT(i, j);
                        } else if ((!isRightBottom(i, j))
                                && (isRightUp(i, j) && isRight(i, j))) {
                            setRightShadeB(i, j);
                        }
                    }
                }
            }
        }
        return false;
    }

    private void setRightShadeT(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = 0; q < scale / 2; q++) {
            boolean bgState = true;
            for (int p = scale - 1; p >= scale / 2; p--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + (i + 1) * scale - length, baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth+ i * scale + p
                                    - (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setRightShadeB(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = scale / 2; q < scale; q++) {
            boolean bgState = true;
            for (int p = scale - 1; p >= scale / 2; p--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + (i + 1) * scale - length, baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    - (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setWhiteRightShadeB(int i, int j) {
        // TODO Auto-generated method stub
        // y=10/(3*scale)x^2 (-1/2*scale,5/6*scale)
        for (int p = scale / 2; p < scale; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + (i + 1)
                    * scale - scale / 3 + min, baseHeight + j * scale + p));
            int r = (int) (ev.getRed() - GRAYSCALE / Amplitude);
            int g = (int) (ev.getGreen() - GRAYSCALE / Amplitude);
            int b = (int) (ev.getBlue() - GRAYSCALE / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + (i + 1) * scale - q,
                            baseHeight + j * scale + p, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff
                            * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setWhiteRightShadeT(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + (i + 1)
                    * scale - scale / 3 + min, baseHeight + j * scale + p));
            int r = (int) (ev.getRed() - GRAYSCALE / Amplitude);
            int g = (int) (ev.getGreen() - GRAYSCALE / Amplitude);
            int b = (int) (ev.getBlue() - GRAYSCALE / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + (i + 1) * scale - q,
                            baseHeight + j * scale + p, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff
                            * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setUpRightShade(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = 0; q < scale / 2; q++) {
            boolean bgState = true;
            for (int p = scale - 1; p >= scale / 2; p--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (q - q * q * 4.0 / (3.0 * scale)) - (scale - 1 - p));
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + (i + 1)
                                * scale
                                - (int) (scale / 2.0 - (q - q * q * 4.0
                                / (3.0 * scale))), baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    - (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setBottomRightShade(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = scale / 2; q < scale; q++) {
            boolean bgState = true;
            for (int p = scale - 1; p >= scale / 2; p--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (q - q * q * 4.0 / (3.0 * scale)) - (scale - 1 - p));
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + (i + 1)
                                * scale
                                - (int) (scale / 2.0 - (q - q * q * 4.0
                                / (3.0 * scale))), baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    - (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setLeftShadeT(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = 0; q < scale / 2; q++) {
            boolean bgState = true;
            for (int p = 0; p < scale / 2; p++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + length, baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    + (length - 1 - k),baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setLeftShadeB(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = scale / 2; q < scale; q++) {
            boolean bgState = true;
            for (int p = 0; p < scale / 2; p++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + length, baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    + (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setWhiteLeftShadeB(int i, int j) {
        // TODO Auto-generated method stub
        // y=10/(3*scale)x^2 (-1/2*scale,5/6*scale)
        for (int p = scale / 2; p < scale; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + i * scale
                    + scale / 3 - min, baseHeight + j * scale + p));
            int r = (int) (ev.getRed() - GRAYSCALE / Amplitude);
            int g = (int) (ev.getGreen() - GRAYSCALE / Amplitude);
            int b = (int) (ev.getBlue() - GRAYSCALE / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + i * scale + q, 
                            baseHeight+ j * scale + p, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setWhiteLeftShadeT(int i, int j) {
        // TODO Auto-generated method stub
        // y=10/(3*scale)x^2 (-1/2*scale,5/6*scale)
        for (int p = 0; p < scale / 2; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + i * scale
                    + scale / 3 - min, baseHeight + j * scale + p));
            int r = (int) (ev.getRed() - GRAYSCALE / Amplitude);
            int g = (int) (ev.getGreen() - GRAYSCALE / Amplitude);
            int b = (int) (ev.getBlue() - GRAYSCALE / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + i * scale + q, 
                            baseHeight+ j * scale + p, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setUpLeftShade(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = 0; q < scale / 2; q++) {
            boolean bgState = true;
            for (int p = 0; p < scale / 2; p++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                       baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (q - q * q * 4.0 / (3.0 * scale)) - p);
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(
                                baseWidth
                                + i
                                * scale
                                + (int) (scale / 2.0 - (q - q * q * 4.0
                                / (3.0 * scale))), baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    + (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setBottomLeftShade(int i, int j) {
        // TODO Auto-generated method stub
        for (int q = scale / 2; q < scale; q++) {
            boolean bgState = true;
            for (int p = 0; p < scale / 2; p++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (q - q * q * 4.0 / (3.0 * scale)) - p);
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(
                                baseWidth
                                + i
                                * scale
                                + (int) (scale / 2.0 - (q - q * q * 4.0
                                / (3.0 * scale))), baseHeight + j
                                * scale + q));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p
                                    + (length - 1 - k), baseHeight + j
                                    * scale + q, new Color(GRAYSCALE + rdiff
                                    * (length - 1 - k), GRAYSCALE + gdiff
                                    * (length - 1 - k), GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setWhiteBottomShadeR(int i, int j) {
        // TODO Auto-generated method stub
        // y=10/(3*scale)x^2 (-1/2*scale,5/6*scale)
        for (int p = scale / 2; p < scale; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + i * scale
                    + p, baseHeight + (j + 1) * scale - scale / 3 + min));
            int r = (int) (ev.getRed() - GRAYSCALE / Amplitude);
            int g = (int) (ev.getGreen() - GRAYSCALE / Amplitude);
            int b = (int) (ev.getBlue() - GRAYSCALE / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ (j + 1) * scale - q, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setWhiteBottomShadeL(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + i * scale
                    + p, baseHeight + (j + 1) * scale - scale / 3 + min));
            int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
            int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
            int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ (j + 1) * scale - q, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setRightBottomShade(int i, int j) {
        // TODO Auto-generated method stub
        // y = x - 4/(3*scale)x^2 (1/2*scale,1/6*scale)
        for (int p = scale / 2; p < scale; p++) {
            boolean bgState = true;
            for (int q = scale - 1; q >= scale / 2; q--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                       baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (p - p * p * 4.0 / (3.0 * scale)) - (scale - 1 - q));
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, 
                                baseHeight
                                + j
                                * scale
                                + (scale - (int) (scale / 2.0 - (p - p * p
                                * 4.0 / (3.0 * scale))))));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    - (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setLeftBottomShade(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            boolean bgState = true;
            for (int q = scale - 1; q >= scale / 2; q--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (p - p * p * 4.0 / (3.0 * scale)) - (scale - 1 - q));
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p,
                                baseHeight
                                + j
                                * scale
                                + (scale - (int) (scale / 2.0 - (p - p * p
                                * 4.0 / (3.0 * scale))))));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    - (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setBottomShadeL(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            boolean bgState = true;
            for (int q = scale - 1; q >= scale / 2; q--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, baseHeight + (j + 1)
                                * scale - length));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    - (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setBottomShadeR(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            boolean bgState = true;
            for (int q = scale - 1; q >= scale / 2; q--) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, baseHeight + (j + 1)
                                * scale - length));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    - (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setWhiteUpShadeR(int i, int j) {
        // TODO Auto-generated method stub
        // y=10/(3*scale)x^2 (-1/2*scale,5/6*scale)
        for (int p = scale / 2; p < scale; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + i * scale
                    + p, baseHeight + j * scale + scale / 3 - min));
            int r = (int) (ev.getRed() - GRAYSCALE / Amplitude);
            int g = (int) (ev.getGreen() - GRAYSCALE / Amplitude);
            int b = (int) (ev.getBlue() - GRAYSCALE / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight+ j * scale + q, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setWhiteUpShadeL(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            int min = (int) (10 / 3.0 * (scale / 2 - p) * (scale / 2 - p) / scale);
            int upLevel = (scale / 2 - (int) Math.sqrt(scale * scale / 4
                    - (scale / 2 - p) * (scale / 2 - p)));
            int length = scale / 3 - min + upLevel;
            if (length == 0) {
                continue;
            }
            Color ev = new Color(resultImage.getRGB(baseWidth + i * scale
                    + p, baseHeight + j * scale + scale / 3 - min));
            int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
            int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
            int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
            int rdiff = r / length;
            int gdiff = g / length;
            int bdiff = b / length;
            for (int q = -scale / 2; q < scale / 3; q++) {
                if (min <= (scale / 3 - q)
                        && ((scale / 2 - p) * (scale / 2 - p) + (q + scale / 2)
                        * (q + scale / 2)) >= scale * scale / 4) {
                    resultImage.setRGB(baseWidth + i * scale + p, 
                            baseHeight + j * scale + q, new Color(GRAYSCALE
                            + rdiff * (q + upLevel), GRAYSCALE + gdiff
                            * (q + upLevel), GRAYSCALE + bdiff * (q + upLevel)).getRGB());
                }
            }
        }
    }

    private void setUpShadeR(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = scale / 2; p < scale; p++) {
            boolean bgState = true;
            for (int q = 0; q < scale / 2; q++) {
                int rgb = resultImage.getRGB(baseWidth+ i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, baseHeight + j * scale
                                + length));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    + (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setUpShadeL(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            boolean bgState = true;
            for (int q = 0; q < scale / 2; q++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 3.0);
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, baseHeight + j * scale
                                + length));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    + (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setRightUpShade(int i, int j) {
        // TODO Auto-generated method stub
        // y = x - 4/(3*scale)x^2 (1/2*scale,1/6*scale)
        for (int p = scale / 2; p < scale; p++) {
            boolean bgState = true;
            for (int q = 0; q < scale / 2; q++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (p - p * p * 4.0 / (3.0 * scale)) - q);
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, 
                                baseHeight
                                + j
                                * scale
                                + (int) (scale / 2.0 - (p - p * p * 4.0
                                / (3.0 * scale)))));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    + (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private void setLeftUpShade(int i, int j) {
        // TODO Auto-generated method stub
        for (int p = 0; p < scale / 2; p++) {
            boolean bgState = true;
            for (int q = 0; q < scale / 2; q++) {
                int rgb = resultImage.getRGB(baseWidth + i * scale + p,
                        baseHeight + j * scale + q);
                if ((rgb != this.backgroundImage.getRGB(baseWidth + i
                        * scale + p, baseHeight + j * scale + q))) {
                    if (bgState == true) {
                        bgState = false;
                        int length = (int) (scale / 2.0
                                - (p - p * p * 4.0 / (3.0 * scale)) - q);
                        if (length == 0) {
                            continue;
                        }
                        Color ev = new Color(resultImage.getRGB(baseWidth
                                + i * scale + p, 
                                baseHeight
                                + j
                                * scale
                                + (int) (scale / 2.0 - (p - p * p * 4.0
                                / (3.0 * scale)))));
                        int r = (int) ((ev.getRed() - GRAYSCALE) / Amplitude);
                        int g = (int) ((ev.getGreen() - GRAYSCALE) / Amplitude);
                        int b = (int) ((ev.getBlue() - GRAYSCALE) / Amplitude);
                        int rdiff = r / length;
                        int gdiff = g / length;
                        int bdiff = b / length;
                        for (int k = length - 1; k >= 0; k--) {
                            resultImage.setRGB(baseWidth + i * scale + p,
                                    baseHeight + j * scale + q
                                    + (length - 1 - k), new Color(
                                    GRAYSCALE + rdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + gdiff
                                    * (length - 1 - k),
                                    GRAYSCALE + bdiff
                                    * (length - 1 - k)).getRGB());
                        }
                    }
                } else {
                    bgState = true;
                }
            }
        }
    }

    private int getFuncVaule(int sv, int ev, double s, double e, int q) {
        // TODO Auto-generated method stub
        return (int) ((ev - sv) / (e - s) * q + sv);
    }

    private boolean isDot(int i, int j) {
        // TODO Auto-generated method stub
        return isRight(i, j) && isLeft(i, j) && isBottom(i, j) && isUp(i, j);
    }

    protected int isInCircle(int p, int q, double i, double j, double k) {
        // TODO Auto-generated method stub
        double r = Math.sqrt((p - i) * (p - i) + (q - j) * (q - j));
        if (r == k) {
            return 2;
        } else if (r > k) {
            return 0;
        } else {
            return 1;
        }
    }

   protected boolean isUp(int i, int j) {
		// TODO Auto-generated method stub
                ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (j > 0) {
			if (m.get(i, j - 1) == 0 || isImage(i, j - 1))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isLeft(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0) {
			if (m.get(i - 1, j) == 0 || isImage(i - 1, j))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isRightUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j > 0) {
			if ((m.get(i + 1, j) == 0 || isImage(i + 1, j))
					&& (m.get(i, j - 1) == 0 || isImage(i, j - 1))
					) {
				return true;
			}
		} else if (i < m.getWidth() - 1) {
			if (m.get(i + 1, j) == 0 || isImage(i + 1, j)) {
				return true;
			}
		} else if (j > 0) {
			if (m.get(i, j - 1) == 0 || isImage(i, j - 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isWhiteRightBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j < m.getHeight() - 1) {
			if ((m.get(i + 1, j) != 0 && !isImage(i + 1, j))
					&& (m.get(i, j + 1) != 0 && !isImage(i, j + 1))
					&& (m.get(i + 1, j + 1) != 0 && !isImage(i + 1, j + 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isWhiteLeftBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j < m.getHeight() - 1) {
			if ((m.get(i - 1, j) != 0 && !isImage(i - 1, j))
					&& (m.get(i, j + 1) != 0 && !isImage(i, j + 1))
					&& (m.get(i - 1, j + 1) != 0 && !isImage(i - 1, j + 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isWhiteRightUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j > 0) {
			if ((m.get(i + 1, j) != 0 && !isImage(i + 1, j))
					&& (m.get(i, j - 1) != 0 && !isImage(i, j - 1))
					&& (m.get(i + 1, j - 1) != 0 && !isImage(i + 1, j - 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isWhiteLeftUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j > 0) {
			if ((m.get(i - 1, j) != 0 && !isImage(i - 1, j))
					&& (m.get(i, j - 1) != 0 && !isImage(i, j - 1))
					&& (m.get(i - 1, j - 1) != 0 && !isImage(i - 1, j - 1))) {
				return true;
			}
		}
		return false;
	}

	protected boolean isRightBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1 && j < m.getHeight() - 1) {
			if ((m.get(i + 1, j) == 0 || isImage(i + 1, j))
					&& (m.get(i, j + 1) == 0 || isImage(i, j + 1))
					) {
				return true;
			}
		} else if (i < m.getWidth() - 1) {
			if (m.get(i + 1, j) == 0 || isImage(i + 1, j)) {
				return true;
			}
		} else if (j < m.getHeight() - 1) {
			if (m.get(i, j + 1) == 0 || isImage(i, j + 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (j < m.getHeight() - 1) {
			if (m.get(i, j + 1) == 0 || isImage(i, j + 1))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isLeftBottom(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j < m.getHeight() - 1) {
			if ((m.get(i - 1, j) == 0 || isImage(i - 1, j))
					&& (m.get(i, j + 1) == 0 || isImage(i, j + 1))
				) {
				return true;
			}
		} else if (i > 0) {
			if (m.get(i - 1, j) == 0 || isImage(i - 1, j)) {
				return true;
			}
		} else if (j < m.getHeight() - 1) {
			if (m.get(i, j + 1) == 0 || isImage(i, j + 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

	protected boolean isRight(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i < m.getWidth() - 1) {
			if (m.get(i + 1, j) == 0 || isImage(i + 1, j))
				return true;
		} else
			return true;
		return false;
	}

	protected boolean isLeftUp(int i, int j) {
		// TODO Auto-generated method stub
		ByteMatrix m = outputMatrix.getQrcode().getMatrix();
		if (i > 0 && j > 0) {
			if ((m.get(i - 1, j) == 0 || isImage(i - 1, j))
					&& (m.get(i, j - 1) == 0 || isImage(i, j - 1))
					) {
				return true;
			}
		} else if (i > 0) {
			if (m.get(i - 1, j) == 0 || isImage(i - 1, j)) {
				return true;
			}
		} else if (j > 0) {
			if (m.get(i, j - 1) == 0 || isImage(i, j - 1)) {
				return true;
			}
		} else
			return true;
		return false;
	}

    protected boolean isImage(int i, int j) {
        // TODO Auto-generated method stub

        for (ImageMosaicMatrix m2 : outputMatrix.getMosaicList()) {
            if (j - m2.getY() >= 0 && j - m2.getY() < m2.getHeight()
                    && i - m2.getX() >= 0 && i - m2.getX() < m2.getWidth()) {
                if (m2.getMatrix()[j - m2.getY()][i - m2.getX()].type == Mosaic.IMAGE) {
                    return true;

                }
            }
        }
        return false;
    }
}
